//**********************************************************************
//	Programmer	-	Sujal Bista
//	File Name	-	GraphicsGL.h
//	Description	:	
//					API handler for openGL
//**********************************************************************


#include "graphicsGL.h"
#include "utilityFunctions.h"

#ifdef _MSC_VER
	#ifdef _DEBUG
		#include <crtdbg.h>
		#include <stdlib.h>
		#define DEBUG_NEW new(_NORMAL_BLOCK ,__FILE__, __LINE__)
		#define new DEBUG_NEW	
	#else
		#define DEBUG_NEW new
	#endif		
#endif

#ifdef _MSC_VER
	#ifdef _DEBUG
		#pragma comment(lib,"glew32.lib")
		#pragma comment(lib,"opengl32.lib")
		#pragma comment(lib,"OpenCL.lib")
	#else
		#pragma comment(lib,"glew32.lib")
		#pragma comment(lib,"opengl32.lib")
		#pragma comment(lib,"OpenCL.lib")
	#endif		
#endif

#define GL_MIN_SUPPORTED_MAJOR_VERSION 4
#define GL_MIN_SUPPORTED_MINOR_VERSION 1

#include<fstream>

#define START_STRING_VERTEX "//VERTEX_SHADER_START"
#define END_STRING_VERTEX "//VERTEX_SHADER_END"
#define START_STRING_HULL "//HULL_SHADER_START"
#define END_STRING_HULL "//HULL_SHADER_END"
#define START_STRING_DOMAIN "//DOMAIN_SHADER_START"
#define END_STRING_DOMAIN "//DOMAIN_SHADER_END"
#define START_STRING_GEOMETRY "//GEOMETRY_SHADER_START"
#define END_STRING_GEOMETRY "//GEOMETRY_SHADER_END"
#define START_STRING_PIXEL "//PIXEL_SHADER_START"
#define END_STRING_PIXEL "//PIXEL_SHADER_END"
#define START_STRING_COMPUTE "//COMPUTE_SHADER_START"
#define END_STRING_COMPUTE "//COMPUTE_SHADER_END"

//constructor
graphicsGL::graphicsGL(void):graphicsBase()
{
	//form related variables
	hWnd=NULL;						// handle to main window
	hDC=NULL;						// handle to main device context
}
		
//initilizes the device
bool graphicsGL::init(deviceBase *gDevice, deviceContextBase *dContext, texture2DBase *renderTarget, texture2DBase *depthStencil,renderTargetViewBase *rTargetView,depthStencilViewBase *dStencilView)
{
	using namespace graphicsDefinitions;

	deviceGL *gDeviceGL=(deviceGL *)gDevice;
	deviceContextGL *dContextGL=(deviceContextGL *)dContext;
	texture2DGL *renderTargetGL=(texture2DGL *)renderTarget;
	texture2DGL *depthStencilGL=(texture2DGL *)depthStencil;
	renderTargetViewGL *rTargetViewGL=(renderTargetViewGL *)rTargetView;
	depthStencilViewGL *dStencilViewGL=(depthStencilViewGL *)dStencilView;


	PIXELFORMATDESCRIPTOR pfd=				// pfd Tells Windows How We Want Things To Be
		{
			sizeof(PIXELFORMATDESCRIPTOR),				// Size Of This Pixel Format Descriptor
			1,											// Version Number
			PFD_DRAW_TO_WINDOW |						// Format Must Support Window
			PFD_SUPPORT_OPENGL |						// Format Must Support OpenGL
			PFD_DOUBLEBUFFER,							// Must Support Double Buffering
			PFD_TYPE_RGBA,								// Request An RGBA Format
			32,											// Select Our Color Depth
			0, 0, 0, 0, 0, 0,							// Color Bits Ignored
			0,											// No Alpha Buffer
			0,											// Shift Bit Ignored
			0,											// No Accumulation Buffer
			0, 0, 0, 0,									// Accumulation Bits Ignored
			16,											// 16 Bit Z-Buffer (Depth Buffer)  
			8,											// 8 Bit Stencil Buffer
			0,											// No Auxiliary Buffer
			PFD_MAIN_PLANE,								// Main Drawing Layer
			0,											// Reserved
			0, 0, 0										// Layer Masks Ignored
		};
	
	//in opengl hDC is used as device with wgl functions
	gDeviceGL->data=hDC;

	// choose best matching pixel format
	int  pixelFormat;
	if (!(pixelFormat = ChoosePixelFormat(gDeviceGL->data, &pfd)))
	{
		outputDebugString("%s(%d): Error: Can't find an appropriate pixel format\n",__FILE__,__LINE__);
		return false;
	}

	// set pixel format to device context
	if(!SetPixelFormat(gDeviceGL->data, pixelFormat,&pfd))
	{
		outputDebugString("%s(%d): Error: Unable to set pixel format\n",__FILE__,__LINE__);
		return false;
	}

	// create the OpenGL rendering context
	if (!(dContextGL->data = wglCreateContext(gDeviceGL->data)))
	{
		outputDebugString("%s(%d): Error: Unable to create OpenGL rendering context\n",__FILE__,__LINE__);
		return false;
	}

	// now make the rendering context the active one
	if(!wglMakeCurrent(gDeviceGL->data, dContextGL->data))
	{
		outputDebugString("%s(%d): Error: Unable to activate OpenGL rendering context\n",__FILE__,__LINE__);
		return false;
	}

	//init glew
	glewInit();

	//get the supported major and minor version
	int majorVersion = 0;
	int minorVersion = 0;
	glGetIntegerv(GL_MAJOR_VERSION, &majorVersion);
	glGetIntegerv(GL_MINOR_VERSION, &minorVersion);

	//check if the hardware supports the version
	if(!(majorVersion>=GL_MIN_SUPPORTED_MAJOR_VERSION && minorVersion>=GL_MIN_SUPPORTED_MINOR_VERSION))
	{
		outputDebugString("%s(%d): Error: GL version not supported\n",__FILE__,__LINE__);
		return false;
	}

	int attributes[] = 
	{
		WGL_CONTEXT_MAJOR_VERSION_ARB, majorVersion, // Set the MAJOR version of OpenGL to latest
		WGL_CONTEXT_MINOR_VERSION_ARB, minorVersion, // Set the MINOR version of OpenGL to latest
		WGL_CONTEXT_FLAGS_ARB, WGL_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB, // Set our OpenGL context to be forward compatible
		WGL_CONTEXT_PROFILE_MASK_ARB, WGL_CONTEXT_CORE_PROFILE_BIT_ARB, 
		0
	};

	if (wglewIsSupported("WGL_ARB_create_context") == 1) 
	{ 
		HGLRC newHRC = wglCreateContextAttribsARB(gDeviceGL->data, NULL, attributes); // Create and OpenGL 3.x context based on the given attributes
		
		if(!newHRC)
		{
			outputDebugString("%s(%d): Error: Unable to create desired OpenGL rendering context\n",__FILE__,__LINE__);
			return false;
		}

		//remove old context
		if(!wglMakeCurrent(gDeviceGL->data, NULL))
		{
			outputDebugString("%s(%d): Error: Unable to activate OpenGL rendering context\n",__FILE__,__LINE__);
			return false;
		}
		
		//delete old context
		if(!wglDeleteContext(dContextGL->data))
		{
			outputDebugString("%s(%d): Error: Unable to free old context\n",__FILE__,__LINE__);
			return false;
		}
		
		//assign the new context
		dContextGL->data=newHRC;	
		
		// now make the rendering context the active one
		if(!wglMakeCurrent(gDeviceGL->data, dContextGL->data))
		{
			outputDebugString("%s(%d): Error: Unable to activate OpenGL rendering context\n",__FILE__,__LINE__);
			return false;
		}
	}
			
	//create a shader object
	dContextGL->shaderObject=glCreateProgram();

	//get openCL platform ID
	if(clGetPlatformIDs(1, &gDeviceGL->clPlatformID, NULL) != CL_SUCCESS)
	{
		outputDebugString("%s(%d): Error: Unable to get openCL platform ID\n",__FILE__,__LINE__);
		return false;
	}

	//Get the devices ID
    if (clGetDeviceIDs(gDeviceGL->clPlatformID, CL_DEVICE_TYPE_GPU, 1, &gDeviceGL->clDeviceID, NULL) != CL_SUCCESS)
    {
        outputDebugString("%s(%d): Error: Unable to get openCL device ID\n",__FILE__,__LINE__);
		return false;
    }

    //Create the context
	int errorCode;
    gDeviceGL->clContext = clCreateContext(0, 1, &gDeviceGL->clDeviceID, NULL, NULL, &errorCode);
    if (errorCode != CL_SUCCESS)
    {
		outputDebugString("%s(%d): Error: Unable to create openCL context\n",__FILE__,__LINE__);
		return false;
    }

    // Create a command-queue
    dContextGL->clCommandQueue = clCreateCommandQueue(gDeviceGL->clContext, gDeviceGL->clDeviceID, 0, &errorCode);
	if (errorCode != CL_SUCCESS)
    {
		outputDebugString("%s(%d): Error: Unable to create openCL command queue\n",__FILE__,__LINE__);
		return false;
    }

	//sync read and write alignment
	glPixelStorei(GL_PACK_ALIGNMENT,4);
	glPixelStorei(GL_UNPACK_ALIGNMENT,4);

	glEnable(GL_DEPTH_TEST);	// Enables Depth Testing
	glDepthFunc(GL_LESS);	// The Type Of Depth Testing To Do
	glShadeModel(GL_SMOOTH);	// Enable Smooth Shading
	glEnable(GL_CULL_FACE);		// Enable Polygon Culling
	glFrontFace(GL_CCW);	// Cull clockwise polygon

	//resizes the output screen
	if(!resize(gDevice,dContext,renderTarget,depthStencil,rTargetView,dStencilView, width,height))
		return false;

	return true;
}
	
//closes the device
bool graphicsGL::close(void)
{
    return true;
}

//resizes the output screen
bool graphicsGL::resize(deviceBase *gDevice, deviceContextBase *dContext, texture2DBase *renderTarget, texture2DBase *depthStencil,renderTargetViewBase *rTargetView,depthStencilViewBase *dStencilView, const unsigned int &_width,const unsigned int &_height)
{
	width=_width;
	height=_height;

	deviceContextGL *dContextGL=(deviceContextGL *)dContext;

	//resizes the output screen
	dContextGL->resize(width,height);

	return true;
}

//swaps back and front buffer
void graphicsGL::swapBuffer(void)
{
	// switch the front and back buffers to display the updated scene
	SwapBuffers(hDC);
}

//sets vsync option
void graphicsGL::setVerticalSync(bool option)
{
	wglSwapIntervalEXT(option);
}

//checks for any error
bool graphicsGL::checkError(void)
{
	GLenum errCode = glGetError();
	if( errCode != GL_NO_ERROR )
	{
		outputDebugString("%s(%d): Opengl Error : %d\n",__FILE__,__LINE__,errCode);
		return false;
	}
	return true;
}

//destructor
graphicsGL::~graphicsGL()
{
	//closes the device
	close();
}

//loads shader text file
char* graphicsGL::readFile(char* fileName)
{
	using namespace std;

	//Open the file passed in
	ifstream in(fileName);

	if(!in)
		return NULL;

	//get the size of the file
	in.seekg(0,ios::end);
	unsigned int fileSize=(unsigned int)in.tellg();
	in.seekg(0);
	in.clear();

	
	char* string = new char[fileSize+1];

	if(!string)
		return NULL;

	in.read(string,fileSize);
	string[in.gcount()]='\0';

	//if read fails
	if(in.bad())
	{
		delete[] string;
		string=NULL;
	}

	// Close our file
	in.close();

	// Return the text file's data
	return string;
}

//compiles shader for the file
bool graphicsGL::compileShaderFromFile(char* fileName,char *entryPoint, char *shaderModel, blobBase* shData)
{
	blobGL* shDataGL=(blobGL *)shData;
	
	//read the shader from the file
	unsigned int len=(unsigned int)strlen(fileName);
	shDataGL->fileName=new char[len+1];
	strcpy(shDataGL->fileName,fileName);
	shDataGL->data=readFile(fileName);

	if(!shDataGL->data)
	{
		outputDebugString("%s(%d): Error: Cannot open shader file %s\n",__FILE__,__LINE__,fileName);
		return false;
	}

	return true;
}

//sets window handler
void graphicsGL::setWindowHandler(const HWND &_hWnd)
{
	hWnd=_hWnd;
	hDC=GetDC(hWnd);		// handle to main device context
}

//checks the shaders status
bool graphicsGL::deviceGL::checkShaderCreationStatusGL(const graphicsDefinitions::SHADER_TYPE &sType, blobGL &shRawDataGL, unsigned int shaderIDGL)
{
	using namespace graphicsDefinitions;
	int result=0,infoLength=0;
	
	//check the status
	glGetShaderiv(shaderIDGL,GL_COMPILE_STATUS, &result);

	//get length of additional info
	glGetShaderiv(shaderIDGL, GL_INFO_LOG_LENGTH, &infoLength);

	if(infoLength>1)
	{
		char *log=new char[infoLength+1];

		//get the additional info
		glGetShaderInfoLog(shaderIDGL, infoLength, NULL, log);

		unsigned int lineNo;
		sscanf(log,"%d(%d)",&lineNo,&lineNo);

		char *startPos=shRawDataGL.data;
		char *endPos=startPos+strlen(startPos);

		switch(sType)
		{
			case SHADER_TYPE_VERTEX:
				{
					char *ePos=strstr(startPos,START_STRING_VERTEX);
					if(ePos)
						endPos=ePos;
					break;
				}
			case SHADER_TYPE_HULL:
				{
					char *ePos=strstr(startPos,START_STRING_HULL);
					if(ePos)
						endPos=ePos;
					break;
				}
			case SHADER_TYPE_DOMAIN:
				{
					char *ePos=strstr(startPos,START_STRING_DOMAIN);
					if(ePos)
						endPos=ePos;
					break;
				}
			case SHADER_TYPE_GEOMETRY:
				{
					char *ePos=strstr(startPos,START_STRING_GEOMETRY);
					if(ePos)
						endPos=ePos;
					break;
				}
			case SHADER_TYPE_PIXEL:
				{
					char *ePos=strstr(startPos,START_STRING_PIXEL);
					if(ePos)
						endPos=ePos;
					break;
				}
			case SHADER_TYPE_COMPUTE:
				{
					char *ePos=strstr(startPos,START_STRING_COMPUTE);
					if(ePos)
						endPos=ePos;
					break;
				}
			default:;
		};

		//count no of new line character
		for(char *currChar=startPos;currChar<endPos;currChar++)
		{
			if(*currChar=='\n')
				lineNo++;
		}

		//print the output
		outputDebugString("%s(%d): Shader Creation Error: %s",shRawDataGL.fileName,lineNo,log);

		delete[] log;
	}

	return (result!=0);
}

//create deferred context
bool graphicsGL::deviceGL::createDeferredContext(deviceContextBase* dcData)
{
	//opengl does not support multi thread deferred context
	return true;
}

//creates vertex shader
bool graphicsGL::deviceGL::createVertexShader(blobBase* shRawData,shaderVertexBase* shData)
{
	blobGL* shRawDataGL=(blobGL*)shRawData;
	shaderVertexGL* shDataGL=(shaderVertexGL*)shData;
	
	// Create the vertex shader
	shDataGL->data = glCreateShader(GL_VERTEX_SHADER);
	
	char *shaderContentStart=strstr(shRawDataGL->data,START_STRING_VERTEX);
	char *shaderContentEnd=strstr(shRawDataGL->data,END_STRING_VERTEX);
	if(shaderContentStart && shaderContentEnd)
	{
		int length=(int)(shaderContentEnd-shaderContentStart);
		glShaderSource(shDataGL->data, 1, (const GLchar **)&shaderContentStart,&length); //specify the source		
	}
	else
		glShaderSource(shDataGL->data, 1, (const GLchar **)&shRawDataGL->data, NULL); //specify the source
	
	//compile the shader
	glCompileShader(shDataGL->data);

	//checks the shaders status
	return (checkShaderCreationStatusGL(graphicsDefinitions::SHADER_TYPE_VERTEX,*shRawDataGL,shDataGL->data));
}

//creates hull shader
bool graphicsGL::deviceGL::createHullShader(blobBase* shRawData,shaderHullBase* shData)
{
	blobGL* shRawDataGL=(blobGL*)shRawData;
	shaderHullGL* shDataGL=(shaderHullGL*)shData;
	// Create the hull shader
	shDataGL->data = glCreateShader(GL_TESS_CONTROL_SHADER);

	char *shaderContentStart=strstr(shRawDataGL->data,START_STRING_HULL);
	char *shaderContentEnd=strstr(shRawDataGL->data,END_STRING_HULL);
	if(shaderContentStart && shaderContentEnd)
	{
		int length=(int)(shaderContentEnd-shaderContentStart);
		glShaderSource(shDataGL->data, 1, (const GLchar **)&shaderContentStart,&length); //specify the source		
	}
	else
		glShaderSource(shDataGL->data, 1, (const GLchar **)&shRawDataGL->data, NULL); //specify the source
	
	//compile the shader
	glCompileShader(shDataGL->data);

	//checks the shaders status
	return (checkShaderCreationStatusGL(graphicsDefinitions::SHADER_TYPE_HULL,*shRawDataGL,shDataGL->data));
}

//creates domain shader
bool graphicsGL::deviceGL::createDomainShader(blobBase* shRawData,shaderDomainBase* shData)
{
	blobGL* shRawDataGL=(blobGL*)shRawData;
	shaderDomainGL* shDataGL=(shaderDomainGL*)shData;
	// Create the domain shader
	shDataGL->data = glCreateShader(GL_TESS_EVALUATION_SHADER);

	char *shaderContentStart=strstr(shRawDataGL->data,START_STRING_DOMAIN);
	char *shaderContentEnd=strstr(shRawDataGL->data,END_STRING_DOMAIN);
	if(shaderContentStart && shaderContentEnd)
	{
		int length=(int)(shaderContentEnd-shaderContentStart);
		glShaderSource(shDataGL->data, 1, (const GLchar **)&shaderContentStart,&length); //specify the source		
	}
	else
		glShaderSource(shDataGL->data, 1, (const GLchar **)&shRawDataGL->data, NULL); //specify the source
	
	//compile the shader
	glCompileShader(shDataGL->data);

	//checks the shaders status
	return (checkShaderCreationStatusGL(graphicsDefinitions::SHADER_TYPE_DOMAIN,*shRawDataGL,shDataGL->data));
}

//creates geometry shader
bool graphicsGL::deviceGL::createGeometryShader(blobBase* shRawData,shaderGeometryBase* shData)
{
	blobGL* shRawDataGL=(blobGL*)shRawData;
	shaderGeometryGL* shDataGL=(shaderGeometryGL*)shData;
	// Create the geometry shader
	shDataGL->data = glCreateShader(GL_GEOMETRY_SHADER);

	char *shaderContentStart=strstr(shRawDataGL->data,START_STRING_GEOMETRY);
	char *shaderContentEnd=strstr(shRawDataGL->data,END_STRING_GEOMETRY);
	if(shaderContentStart && shaderContentEnd)
	{
		int length=(int)(shaderContentEnd-shaderContentStart);
		glShaderSource(shDataGL->data, 1, (const GLchar **)&shaderContentStart,&length); //specify the source		
	}
	else
		glShaderSource(shDataGL->data, 1, (const GLchar **)&shRawDataGL->data, NULL); //specify the source
	
	//compile the shader
	glCompileShader(shDataGL->data);

	//checks the shaders status
	return (checkShaderCreationStatusGL(graphicsDefinitions::SHADER_TYPE_GEOMETRY,*shRawDataGL,shDataGL->data));
}

//creates pixel shader
bool graphicsGL::deviceGL::createPixelShader(blobBase* shRawData,shaderPixelBase* shData)
{
	blobGL* shRawDataGL=(blobGL*)shRawData;
	shaderPixelGL* shDataGL=(shaderPixelGL*)shData;
	// Create the pixel shader
	shDataGL->data = glCreateShader(GL_FRAGMENT_SHADER);

	char *shaderContentStart=strstr(shRawDataGL->data,START_STRING_PIXEL);
	char *shaderContentEnd=strstr(shRawDataGL->data,END_STRING_PIXEL);
	if(shaderContentStart && shaderContentEnd)
	{
		int length=(int)(shaderContentEnd-shaderContentStart);
		glShaderSource(shDataGL->data, 1, (const GLchar **)&shaderContentStart,&length); //specify the source		
	}
	else
		glShaderSource(shDataGL->data, 1, (const GLchar **)&shRawDataGL->data, NULL); //specify the source
	
	//compile the shader
	glCompileShader(shDataGL->data);

	//checks the shaders status
	return (checkShaderCreationStatusGL(graphicsDefinitions::SHADER_TYPE_PIXEL,*shRawDataGL,shDataGL->data));
}

//creates compute shader
bool graphicsGL::deviceGL::createComputeShader(blobBase* shRawData,shaderComputeBase* shData)
{
	blobGL* shRawDataGL=(blobGL*)shRawData;
	shaderComputeGL* shDataGL=(shaderComputeGL*)shData;
	
	// Create the compute shader
	int errorCode;
	
	char *shaderContentStart=strstr(shRawDataGL->data,START_STRING_COMPUTE);
	char *shaderContentEnd=strstr(shRawDataGL->data,END_STRING_COMPUTE);
	if(shaderContentStart && shaderContentEnd)
	{
		size_t sourceLen=(int)(shaderContentEnd-shaderContentStart);

		// Create the program
		shDataGL->data= clCreateProgramWithSource(clContext, 1, (const char **)&shaderContentStart, &sourceLen, &errorCode);
		if (errorCode != CL_SUCCESS)
		{
			outputDebugString("%s(%d): Error: OpenCL program creation\n",__FILE__,__LINE__);
			return false;
		}
		
	}
	else
	{
		size_t sourceLen=strlen(shRawDataGL->data);

		// Create the program
		shDataGL->data= clCreateProgramWithSource(clContext, 1, (const char **)&shRawDataGL->data, &sourceLen, &errorCode);
		if (errorCode != CL_SUCCESS)
		{
			outputDebugString("%s(%d): Error: OpenCL program creation\n",__FILE__,__LINE__);
			return false;
		}
	}

	//compile the program
    if (clBuildProgram(shDataGL->data, 0, NULL, NULL, NULL, NULL) != CL_SUCCESS)
    {
		outputDebugString("%s(%d): Error: OpenCL program compilation\n",__FILE__,__LINE__);
        return false;
    }

    // Create the kernel
    shDataGL->clKernel = clCreateKernel(shDataGL->data, "mainCL", &errorCode);
    if (errorCode != CL_SUCCESS)
    {
		outputDebugString("%s(%d): Error: OpenCL kernel creation\n",__FILE__,__LINE__);
        return false;
    }
	
	return true;
}

//creates input layout
bool graphicsGL::deviceGL::createInputLayout(inputElementDesc *inputDesc, unsigned int inputDescCount,blobBase *shData,inputLayoutBase *inLayData)
{
	inputLayoutGL* inLayDataGL=(inputLayoutGL*)inLayData;
	blobGL* shDataGL=(blobGL*)shData;
	using namespace graphicsDefinitions;
	
	if(!inputDescCount)
		return false;

	//generate vao
	glGenVertexArrays(1, &(inLayDataGL->data));
    
	//allocate memory
	inLayDataGL->desc=new inputElementDesc[inputDescCount];
	if(!inLayDataGL->desc)
		return false;
	inLayDataGL->descCount=inputDescCount;

	//copy data
	memcpy(inLayDataGL->desc,inputDesc,sizeof(inputElementDesc)*inLayDataGL->descCount);

	return true;
}

//creates buffer in gpu
bool graphicsGL::deviceGL::createBuffer(bufferDesc desc, void *pSysMem, unsigned int sysMemPitch, unsigned int sysMemSlicePitch, bufferBase *bData)
{
	bufferGL *bDataGL=(bufferGL *)bData;
	using namespace graphicsDefinitions;
	
	bDataGL->size=desc.byteWidth;

	//create opencl buffer
	if(desc.bindFlags & graphicsDefinitions::BIND_FLAG_UNORDERED_ACCESS)
	{
		bDataGL->bufferType=bufferGL::BUFFER_TYPE_CL;

		int errorCode;

		if(pSysMem)
			bDataGL->clBuffer = clCreateBuffer(clContext, CL_MEM_READ_WRITE|CL_MEM_COPY_HOST_PTR, bDataGL->size, pSysMem, &errorCode);
		else
			bDataGL->clBuffer = clCreateBuffer(clContext, CL_MEM_READ_WRITE, bDataGL->size, NULL, &errorCode);
		
		if(errorCode!=CL_SUCCESS)
		{
			outputDebugString("%s(%d): Error: Allocating openCL memory.\n",__FILE__,__LINE__);
			return false;
		}
		return true;
	}

	//staging memory is cpu memory
	if(desc.usage==graphicsDefinitions::USAGE_STAGING)
	{
		bDataGL->bufferType=bufferGL::BUFFER_TYPE_CPU;
		bDataGL->cpuBuffer=new char[bDataGL->size];
		if(!bDataGL->cpuBuffer)
		{
			outputDebugString("%s(%d): Error: Allocating staging memory.\n",__FILE__,__LINE__);
			return false;
		}
		return true;
	}
	
	//only currently used targets are added
	//more needs to be added
	bDataGL->target=GL_TEXTURE_BUFFER;
	bDataGL->usage=GL_DYNAMIC_DRAW;
	
	switch(desc.bindFlags)
	{
		case BIND_FLAG_VERTEX_BUFFER:
			bDataGL->target=GL_ARRAY_BUFFER;
			bDataGL->bufferType=bufferGL::BUFFER_TYPE_GL;
			break;
		case BIND_FLAG_INDEX_BUFFER:
			bDataGL->target=GL_ELEMENT_ARRAY_BUFFER;
			bDataGL->bufferType=bufferGL::BUFFER_TYPE_GL;
			break;
		case BIND_FLAG_CONSTANT_BUFFER:
			bDataGL->target=GL_UNIFORM_BUFFER;
			bDataGL->bufferType=bufferGL::BUFFER_TYPE_GL;
			break;
	};

	glGenBuffers(1,&bDataGL->glBuffer);//generate ID
	glBindBuffer(bDataGL->target, bDataGL->glBuffer);//bind vbo buffer
	glBufferData(bDataGL->target, bDataGL->size, pSysMem, bDataGL->usage);//create space

	return true;
}

//creates 1D texture
bool graphicsGL::deviceGL::createTexture1D(texture1DDesc desc, void *pSysMem, unsigned int sysMemPitch, unsigned int sysMemSlicePitch, texture1DBase *tData)
{
	texture1DGL *tDataGL=(texture1DGL *)tData;
	//TODO
	return false;
}
//creates 2D texture
bool graphicsGL::deviceGL::createTexture2D(texture2DDesc desc, void *pSysMem, unsigned int sysMemPitch, unsigned int sysMemSlicePitch, texture2DBase *tData)
{
	texture2DGL *tDataGL=(texture2DGL *)tData;
	
	tDataGL->textureTarget=GL_TEXTURE_2D;
	glGenTextures(1, &tDataGL->data);
	glBindTexture(tDataGL->textureTarget, tDataGL->data);
	tDataGL->internalFormat=GL_RGBA;
	tDataGL->format=GL_BGRA;
	tDataGL->dataType=GL_UNSIGNED_BYTE;

	switch(desc.format)
	{
		case graphicsDefinitions::DATA_FORMAT_R8G8B8A8_UNORM:
			tDataGL->internalFormat=GL_RGBA;
			tDataGL->format=GL_RGBA;
			tDataGL->dataType=GL_UNSIGNED_BYTE;
			break;
		case graphicsDefinitions::DATA_FORMAT_R32G32B32_FLOAT:
			tDataGL->internalFormat=GL_RGB;
			tDataGL->format=GL_RGB;
			tDataGL->dataType=GL_FLOAT;
			break;
		case graphicsDefinitions::DATA_FORMAT_R32G32B32A32_FLOAT:
			tDataGL->internalFormat=GL_RGBA;
			tDataGL->format=GL_RGBA;
			tDataGL->dataType=GL_FLOAT;
			break;
	};

	glTexImage2D(tDataGL->textureTarget,0,tDataGL->internalFormat,desc.width,desc.height,0,tDataGL->format,tDataGL->dataType,(void *)pSysMem);	//save the data
	glGenerateMipmap(tDataGL->textureTarget);//enable mipmaping
	return true;
}
//creates 3D texture
bool graphicsGL::deviceGL::createTexture3D(texture3DDesc desc, void *pSysMem, unsigned int sysMemPitch, unsigned int sysMemSlicePitch, texture3DBase *tData)
{
	texture3DGL *tDataGL=(texture3DGL *)tData;
	//TODO
	return false;
}

//creates shader resource view from file
bool graphicsGL::deviceGL::createShaderResourceViewFromFile(char* fileName, shaderResourceViewBase * srvData)
{
	shaderResourceViewGL *srvDataGL=(shaderResourceViewGL *)srvData;
	
	picture image;
	//open the texture
	if(!image.readBMP(fileName))
	{
		outputDebugString("%s(%d): Error: Cannot open file : %d\n",__FILE__,__LINE__,fileName);
		return false;
	}

	//flip the image
	image.flipVertically();

	//create texture 2D
	texture2DGL *tex2D=new texture2DGL; 

	//save the resource data
	srvDataGL->resourcePtr=tex2D;
	srvDataGL->freeResource=true;

	

	tex2D->textureTarget=GL_TEXTURE_2D;
	glGenTextures(1, &tex2D->data);
	glBindTexture(tex2D->textureTarget, tex2D->data);
	tex2D->internalFormat=GL_RGBA;
	tex2D->format=GL_BGRA;
	tex2D->dataType=GL_UNSIGNED_BYTE;

	switch(image.format)
	{
		case picture::IMAGE_FORMAT_RGB:
			tex2D->internalFormat=GL_RGB;
			tex2D->format=GL_RGB;
			tex2D->dataType=GL_UNSIGNED_BYTE;
			break;
		case picture::IMAGE_FORMAT_RGBA:
			tex2D->internalFormat=GL_RGBA;
			tex2D->format=GL_RGBA;
			tex2D->dataType=GL_UNSIGNED_BYTE;
			break;
		case picture::IMAGE_FORMAT_BGR:
			tex2D->internalFormat=GL_RGB;
			tex2D->format=GL_BGR;
			tex2D->dataType=GL_UNSIGNED_BYTE;
			break;
		case picture::IMAGE_FORMAT_BGRA:
			tex2D->internalFormat=GL_RGBA;
			tex2D->format=GL_BGRA;
			tex2D->dataType=GL_UNSIGNED_BYTE;
			break;
		case picture::IMAGE_FORMAT_RGB_FLOAT_32:
			tex2D->internalFormat=GL_RGB32F;
			tex2D->format=GL_RGB;
			tex2D->dataType=GL_FLOAT;
			break;
		case picture::IMAGE_FORMAT_RGBA_FLOAT_32:
			tex2D->internalFormat=GL_RGBA32F;
			tex2D->format=GL_RGBA;
			tex2D->dataType=GL_FLOAT;
			break;
		case picture::IMAGE_FORMAT_BGR_FLOAT_32:
			tex2D->internalFormat=GL_RGB32F;
			tex2D->format=GL_BGR;
			tex2D->dataType=GL_FLOAT;
			break;
		case picture::IMAGE_FORMAT_BGRA_FLOAT_32:
			tex2D->internalFormat=GL_RGBA32F;
			tex2D->format=GL_BGRA;
			tex2D->dataType=GL_FLOAT;
			break;
		case picture::IMAGE_FORMAT_BC1:	//DXT1
		case picture::IMAGE_FORMAT_BC2:	//DXT3
		case picture::IMAGE_FORMAT_BC3:	//DXT5
		case picture::IMAGE_FORMAT_BC4:
		case picture::IMAGE_FORMAT_BC5:
		case picture::IMAGE_FORMAT_BC6:
		case picture::IMAGE_FORMAT_BC7:
		case picture::IMAGE_FORMAT_DEPTH_8:
		case picture::IMAGE_FORMAT_DEPTH_16:
		case picture::IMAGE_FORMAT_DEPTH_24:
		case picture::IMAGE_FORMAT_DEPTH_32:
			break;
	};

	glTexImage2D(tex2D->textureTarget,0,tex2D->internalFormat,image.width,image.height,0,tex2D->format,tex2D->dataType,(void *)image.data);	//save the data
	glGenerateMipmap(tex2D->textureTarget);//enable mipmaping
	return true;
}

//creates shader resource view. param0, param1, param2, param3 depends on the dimension type. Please refer to dx version for params
bool graphicsGL::deviceGL::createShaderResourceView(resourceBase *bData, graphicsDefinitions::DATA_FORMAT format, graphicsDefinitions::SRV_DIMENSION dimension, unsigned int param0, unsigned int param1, unsigned int param2, unsigned int param3, shaderResourceViewBase* srvData)
{
	//resourceGL *bDataGL=(resourceGL *)bData;
	using namespace graphicsDefinitions;
	shaderResourceViewGL *srvDataGL=(shaderResourceViewGL *)srvData;
	srvDataGL->resourcePtr=bData;
	srvDataGL->freeResource=false;

	//srvDataGL->data=bData->
	//srvDataGL->data=somehow i need to use the bind texture id

	//srvDataGL->textureTarget=GL_TEXTURE_2D;
	//srvDataGL->internalFormat=GL_RGBA;
	//srvDataGL->format=GL_RGBA;
	//srvDataGL->dataType=GL_UNSIGNED_BYTE;

	//switch(dimension)
	//{
	//	//case SRV_DIMENSION_UNKNOWN:         
	//	//case SRV_DIMENSION_BUFFER:
	//	case SRV_DIMENSION_TEXTURE1D:
	//		srvDataGL->textureTarget=GL_TEXTURE_1D;
	//		break;
	//	//case SRV_DIMENSION_TEXTURE1DARRAY:
	//	case SRV_DIMENSION_TEXTURE2D:
	//		srvDataGL->textureTarget=GL_TEXTURE_2D;
	//		break;
	//	//case SRV_DIMENSION_TEXTURE2DARRAY:
	//	//case SRV_DIMENSION_TEXTURE2DMS:
	//	//case SRV_DIMENSION_TEXTURE2DMSARRAY:
	//	case SRV_DIMENSION_TEXTURE3D:
	//		srvDataGL->textureTarget=GL_TEXTURE_3D;
	//		break;
	//	//case SRV_DIMENSION_TEXTURECUBE:
	//	//case SRV_DIMENSION_TEXTURECUBEARRAY:
	//	//case SRV_DIMENSION_BUFFEREX:
	//}

	//switch(format)
	//{
	//	case DATA_FORMAT_R8G8B8A8_UNORM:
	//		srvDataGL->internalFormat=GL_RGBA;
	//		srvDataGL->format=GL_RGBA;
	//		srvDataGL->dataType=GL_UNSIGNED_BYTE;
	//		break;
	//	case DATA_FORMAT_B8G8R8A8_UNORM:
	//		srvDataGL->internalFormat=GL_RGBA;
	//		srvDataGL->format=GL_BGRA;
	//		srvDataGL->dataType=GL_UNSIGNED_BYTE;
	//		break;
	//	case DATA_FORMAT_R32G32B32_FLOAT:
	//		srvDataGL->internalFormat=GL_RGB32F;
	//		srvDataGL->format=GL_RGB;
	//		srvDataGL->dataType=GL_FLOAT;
	//		break;
	//	case DATA_FORMAT_R32G32B32A32_FLOAT:
	//		srvDataGL->internalFormat=GL_RGBA32F;
	//		srvDataGL->format=GL_RGBA;
	//		srvDataGL->dataType=GL_FLOAT;
	//		break;
	//};

	return true;
}

//creates unordered access view. param0, param1, param2 depends on the dimension type. Please refer to dx version for params
bool graphicsGL::deviceGL::createUnorderedAccessView(resourceBase *bData, graphicsDefinitions::DATA_FORMAT format, graphicsDefinitions::UAV_DIMENSION dimension, unsigned int param0, unsigned int param1, unsigned int param2, unorderedAccessViewBase* uavData)
{
	//resourceGL *bDataGL=(resourceGL *)bData;
	unorderedAccessViewGL *uavDataGL=(unorderedAccessViewGL *)uavData;
	uavDataGL->resourcePtr=bData;
	return true;
}

//creates sampler state
bool graphicsGL::deviceGL::createSamplerState(graphicsDefinitions::FILTER filter,	graphicsDefinitions::TEXTURE_ADDRESS_MODE addMode[3], float mipLODBias, unsigned int maxAnisotropy, graphicsDefinitions::COMPARISON_FUNC comparisonFunc, float borderColor[4], float minLOD, float maxLOD, samplerStateBase *ssBase)
{
	samplerStateGL *ssBaseGL=(samplerStateGL *)ssBase;

	using namespace graphicsDefinitions;
	//create and bind sampler
	glGenSamplers(1, &ssBaseGL->data);
	switch(filter)
	{
		case FILTER_MIN_MAG_MIP_POINT:
			glSamplerParameteri(ssBaseGL->data,GL_TEXTURE_MAG_FILTER,GL_NEAREST); 
			glSamplerParameteri(ssBaseGL->data,GL_TEXTURE_MIN_FILTER,GL_NEAREST);
			break;
		case FILTER_MIN_MAG_POINT_MIP_LINEAR:
			glSamplerParameteri(ssBaseGL->data,GL_TEXTURE_MAG_FILTER,GL_NEAREST); 
			glSamplerParameteri(ssBaseGL->data,GL_TEXTURE_MIN_FILTER,GL_NEAREST_MIPMAP_LINEAR);
			break;
		case FILTER_MIN_POINT_MAG_LINEAR_MIP_POINT:
			glSamplerParameteri(ssBaseGL->data,GL_TEXTURE_MAG_FILTER,GL_LINEAR); 
			glSamplerParameteri(ssBaseGL->data,GL_TEXTURE_MIN_FILTER,GL_NEAREST_MIPMAP_NEAREST);
			break;
		case FILTER_MIN_POINT_MAG_MIP_LINEAR:
			glSamplerParameteri(ssBaseGL->data,GL_TEXTURE_MAG_FILTER,GL_LINEAR); 
			glSamplerParameteri(ssBaseGL->data,GL_TEXTURE_MIN_FILTER,GL_NEAREST_MIPMAP_LINEAR);
			break;
		case FILTER_MIN_LINEAR_MAG_MIP_POINT:
			glSamplerParameteri(ssBaseGL->data,GL_TEXTURE_MAG_FILTER,GL_NEAREST); 
			glSamplerParameteri(ssBaseGL->data,GL_TEXTURE_MIN_FILTER,GL_LINEAR_MIPMAP_NEAREST);
			break;
		case FILTER_MIN_LINEAR_MAG_POINT_MIP_LINEAR:
			glSamplerParameteri(ssBaseGL->data,GL_TEXTURE_MAG_FILTER,GL_NEAREST); 
			glSamplerParameteri(ssBaseGL->data,GL_TEXTURE_MIN_FILTER,GL_LINEAR_MIPMAP_LINEAR);
			break;
		case FILTER_MIN_MAG_LINEAR_MIP_POINT:
			glSamplerParameteri(ssBaseGL->data,GL_TEXTURE_MAG_FILTER,GL_LINEAR); 
			glSamplerParameteri(ssBaseGL->data,GL_TEXTURE_MIN_FILTER,GL_LINEAR_MIPMAP_NEAREST);
			break;
		case FILTER_MIN_MAG_MIP_LINEAR:
			glSamplerParameteri(ssBaseGL->data,GL_TEXTURE_MAG_FILTER,GL_LINEAR); 
			glSamplerParameteri(ssBaseGL->data,GL_TEXTURE_MIN_FILTER,GL_LINEAR_MIPMAP_LINEAR);
			break;

		case FILTER_ANISOTROPIC:
		case FILTER_COMPARISON_MIN_MAG_MIP_POINT:
		case FILTER_COMPARISON_MIN_MAG_POINT_MIP_LINEAR:
		case FILTER_COMPARISON_MIN_POINT_MAG_LINEAR_MIP_POINT:
		case FILTER_COMPARISON_MIN_POINT_MAG_MIP_LINEAR:
		case FILTER_COMPARISON_MIN_LINEAR_MAG_MIP_POINT:
		case FILTER_COMPARISON_MIN_LINEAR_MAG_POINT_MIP_LINEAR:
		case FILTER_COMPARISON_MIN_MAG_LINEAR_MIP_POINT:
		case FILTER_COMPARISON_ANISOTROPIC:
		case FILTER_TEXT_1BIT:
		case FILTER_COMPARISON_MIN_MAG_MIP_LINEAR:
			glSamplerParameteri(ssBaseGL->data,GL_TEXTURE_MAG_FILTER,GL_LINEAR); 
			glSamplerParameteri(ssBaseGL->data,GL_TEXTURE_MIN_FILTER,GL_LINEAR_MIPMAP_LINEAR); 
			break;
		
	}
	
	//different clamp modes
	switch(addMode[0])
	{
		case TEXTURE_ADDRESS_MODE_WRAP:
			glSamplerParameteri(ssBaseGL->data,GL_TEXTURE_WRAP_S,GL_REPEAT); 
			break;
		case TEXTURE_ADDRESS_MODE_MIRROR:
			glSamplerParameteri(ssBaseGL->data,GL_TEXTURE_WRAP_S,GL_MIRRORED_REPEAT); 
			break;
		case TEXTURE_ADDRESS_MODE_CLAMP:
			glSamplerParameteri(ssBaseGL->data,GL_TEXTURE_WRAP_S,GL_CLAMP_TO_EDGE); 
			break;
		case TEXTURE_ADDRESS_MODE_BORDER:
			glSamplerParameteri(ssBaseGL->data,GL_TEXTURE_WRAP_S,GL_CLAMP_TO_BORDER); 
			break;
		case TEXTURE_ADDRESS_MODE_MIRROR_ONCE:
			glSamplerParameteri(ssBaseGL->data,GL_TEXTURE_WRAP_S,GL_MIRRORED_REPEAT); 
			break;
	}

	switch(addMode[1])
	{
		case TEXTURE_ADDRESS_MODE_WRAP:
			glSamplerParameteri(ssBaseGL->data,GL_TEXTURE_WRAP_T,GL_REPEAT); 
			break;
		case TEXTURE_ADDRESS_MODE_MIRROR:
			glSamplerParameteri(ssBaseGL->data,GL_TEXTURE_WRAP_T,GL_MIRRORED_REPEAT); 
			break;
		case TEXTURE_ADDRESS_MODE_CLAMP:
			glSamplerParameteri(ssBaseGL->data,GL_TEXTURE_WRAP_T,GL_CLAMP_TO_EDGE); 
			break;
		case TEXTURE_ADDRESS_MODE_BORDER:
			glSamplerParameteri(ssBaseGL->data,GL_TEXTURE_WRAP_T,GL_CLAMP_TO_BORDER); 
			break;
		case TEXTURE_ADDRESS_MODE_MIRROR_ONCE:
			glSamplerParameteri(ssBaseGL->data,GL_TEXTURE_WRAP_T,GL_MIRRORED_REPEAT); 
			break;
	}

	switch(addMode[2])
	{
		case TEXTURE_ADDRESS_MODE_WRAP:
			glSamplerParameteri(ssBaseGL->data,GL_TEXTURE_WRAP_R,GL_REPEAT); 
			break;
		case TEXTURE_ADDRESS_MODE_MIRROR:
			glSamplerParameteri(ssBaseGL->data,GL_TEXTURE_WRAP_R,GL_MIRRORED_REPEAT); 
			break;
		case TEXTURE_ADDRESS_MODE_CLAMP:
			glSamplerParameteri(ssBaseGL->data,GL_TEXTURE_WRAP_R,GL_CLAMP_TO_EDGE); 
			break;
		case TEXTURE_ADDRESS_MODE_BORDER:
			glSamplerParameteri(ssBaseGL->data,GL_TEXTURE_WRAP_R,GL_CLAMP_TO_BORDER); 
			break;
		case TEXTURE_ADDRESS_MODE_MIRROR_ONCE:
			glSamplerParameteri(ssBaseGL->data,GL_TEXTURE_WRAP_R,GL_MIRRORED_REPEAT); 
			break;
	}

	glSamplerParameterf(ssBaseGL->data,GL_TEXTURE_LOD_BIAS,mipLODBias); //lod bias
	//maxAnisotrop //need to add max anisotropy

	switch(comparisonFunc)
	{
		case COMPARISON_FUNC_NEVER:
			glSamplerParameteri(ssBaseGL->data,GL_TEXTURE_COMPARE_FUNC,GL_NEVER);
			break;
		case COMPARISON_FUNC_LESS:
			glSamplerParameteri(ssBaseGL->data,GL_TEXTURE_COMPARE_FUNC,GL_LESS);
			break;
		case COMPARISON_FUNC_EQUAL:
			glSamplerParameteri(ssBaseGL->data,GL_TEXTURE_COMPARE_FUNC,GL_EQUAL);
			break;
		case COMPARISON_FUNC_LESS_EQUAL:
			glSamplerParameteri(ssBaseGL->data,GL_TEXTURE_COMPARE_FUNC,GL_LEQUAL);
			break;
		case COMPARISON_FUNC_GREATER:
			glSamplerParameteri(ssBaseGL->data,GL_TEXTURE_COMPARE_FUNC,GL_GREATER);
			break;
		case COMPARISON_FUNC_NOT_EQUAL:
			glSamplerParameteri(ssBaseGL->data,GL_TEXTURE_COMPARE_FUNC,GL_NOTEQUAL);
			break;
		case COMPARISON_FUNC_GREATER_EQUAL:
			glSamplerParameteri(ssBaseGL->data,GL_TEXTURE_COMPARE_FUNC,GL_GEQUAL);
			break;
		case COMPARISON_FUNC_ALWAYS:
			glSamplerParameteri(ssBaseGL->data,GL_TEXTURE_COMPARE_FUNC,GL_ALWAYS);
			break;
	};

	glSamplerParameterfv(ssBaseGL->data,GL_TEXTURE_BORDER_COLOR,borderColor);//set border
	glSamplerParameterf(ssBaseGL->data,GL_TEXTURE_MIN_LOD,minLOD);//min lod
	glSamplerParameterf(ssBaseGL->data,GL_TEXTURE_MAX_LOD,maxLOD);//max lod
	return true;
}

//creates rasterizer state
bool graphicsGL::deviceGL::createRasterizerState(graphicsDefinitions::FILL_MODE fillMode,graphicsDefinitions::CULL_MODE cullMode,bool frontCounterClockwise,int depthBias,float depthBiasClamp,float slopeScaledDepthBias,bool depthClipEnable, bool scissorEnable, bool multisampleEnable, bool antialiasedLineEnable,	rasterizerStateBase *rsData)
{
	rasterizerStateGL *rsDataGL=(rasterizerStateGL *)rsData;
	
	//copy all the data
	rsDataGL->fillMode=fillMode;
	rsDataGL->cullMode=cullMode;
	rsDataGL->frontCounterClockwise=frontCounterClockwise;
	rsDataGL->depthBias=depthBias;
	rsDataGL->depthBiasClamp=depthBiasClamp;
	rsDataGL->slopeScaledDepthBias=slopeScaledDepthBias;
	rsDataGL->depthClipEnable=depthClipEnable;
	rsDataGL->scissorEnable=scissorEnable;
	rsDataGL->multisampleEnable=multisampleEnable;
	rsDataGL->antialiasedLineEnable=antialiasedLineEnable;

	return true;
}

//creates a blend state
bool graphicsGL::deviceGL::createBlendState(const blendDesc *bStateDesc,blendStateBase *bStateData)
{
	return false;
}

//resizes the output screen
bool graphicsGL::deviceContextGL::resize(const unsigned int &_width,const unsigned int &_height)
{
	//set the viewport for the context
	glViewport(0,0,_width,_height);	// Reset The Current Viewport

	return true;
}

//Restore all default settings of the device context
void graphicsGL::deviceContextGL::clearState(void)
{

}

//create a command list and record command
bool graphicsGL::deviceContextGL::finishCommandList(bool restoreDeferredContextState, commandListBase* clData)
{
	//opengl does not support multi thread deferred context
	return true;
}
//queues command from command list to the devic
void graphicsGL::deviceContextGL::executeCommandList(commandListBase* clData, bool restoreContextState)
{
	//opengl does not support multi thread deferred context
}

//sets input layout
void graphicsGL::deviceContextGL::setInputLayout(inputLayoutBase *inLayData)
{
	inputLayoutGL* inLayDataGL=(inputLayoutGL*)inLayData;

	//save the input layout to current layout list
	//make sure it is not deleted and still used
	vertexLayout=inLayDataGL;	
}

//updates sub resource
void graphicsGL::deviceContextGL::updateSubResource(resourceBase *destinationBuffer, unsigned int destinationSubresource, const box *destinationBox, const void *sourceData, unsigned int sourceRowPitch, unsigned int sourceDepthPitch)
{
	using namespace graphicsDefinitions;

	//TODO
	//use destinationSubresource and destinationBox to find the offset pos	

	bufferGL *bufferDatasGL=dynamic_cast<bufferGL *>(destinationBuffer);
	if(bufferDatasGL!=NULL)
	{
	
		unsigned int offset=0;
	
		//bind the buffer
		glBindBuffer(bufferDatasGL->target, bufferDatasGL->glBuffer);

		//update the data
		glBufferSubData(bufferDatasGL->target, offset, bufferDatasGL->size, sourceData);
		return;
	}

	texture2DGL *texture2GL=dynamic_cast<texture2DGL *>(destinationBuffer);
	if(texture2GL!=NULL)
	{
		glTexImage2D(texture2GL->textureTarget,0,texture2GL->internalFormat,destinationBox->right,destinationBox->bottom,0,texture2GL->format,texture2GL->dataType,(void *)sourceData);	//save the data
		glGenerateMipmap(texture2GL->textureTarget);//enable mipmaping

	}
}
//copies one buffer to another
void graphicsGL::deviceContextGL::copyResource( resourceBase *dest, resourceBase *src)
{
	bufferGL *destGL=(bufferGL *)dest;
	bufferGL *srcGL=(bufferGL *)src;

	if(destGL->bufferType!=bufferGL::BUFFER_TYPE_CPU || srcGL->bufferType!=bufferGL::BUFFER_TYPE_CL)
		return;

	//copy minimum size
	size_t size=MIN(destGL->size,srcGL->size);

	//Synchronous/blocking read of results, and check accumulated errors
	if(clEnqueueReadBuffer(clCommandQueue, srcGL->clBuffer, CL_TRUE, 0, size, destGL->cpuBuffer, 0, NULL, NULL) != CL_SUCCESS)
		outputDebugString("%s(%d): Error: Error copying resources.\n",__FILE__,__LINE__);
}
//maps the data
void *graphicsGL::deviceContextGL::map(resourceBase *bData, unsigned int subresource, graphicsDefinitions::MAP mapType,unsigned int &rowPitch, unsigned int &depthPitch)
{
	bufferGL *destGL=(bufferGL *)bData;
	
	if(destGL->bufferType==bufferGL::BUFFER_TYPE_CPU)
		return destGL->cpuBuffer;

	if(destGL->bufferType==bufferGL::BUFFER_TYPE_GL)
	{
		glBindBuffer(destGL->target, destGL->glBuffer);//bind vbo buffer
		return glMapBuffer(destGL->target,GL_READ_WRITE_ARB);
	}

	return NULL;
}
//unmap the data
void graphicsGL::deviceContextGL::unmap( resourceBase *bData, unsigned int subresource)
{
	bufferGL *destGL=(bufferGL *)bData;	
	if(destGL->bufferType==bufferGL::BUFFER_TYPE_GL)
		glUnmapBufferARB(destGL->target);	//unmap the buffer
}

//sets vertex buffer
void graphicsGL::deviceContextGL::setVertexBuffers(unsigned int startSlot,unsigned int bufferCount, bufferBase *bufferDatas,unsigned int strides,unsigned int offsets)
{
	bufferGL *bufferDatasGL=(bufferGL *)bufferDatas;

	using namespace graphicsDefinitions;

	//bind the vao
	glBindVertexArray(vertexLayout->data);

	//bind the buffer
	glBindBuffer(bufferDatasGL->target, bufferDatasGL->glBuffer);

	//define size and data type
	unsigned int dataSize=0;
	unsigned int dataType=0;
	unsigned int sizeInBytes=0;
	unsigned int currentOffset=offsets;

	for(unsigned int i=0;i<vertexLayout->descCount;i++)
	{
		//get the current description
		inputElementDesc &currDesc=vertexLayout->desc[i];

		//find the correct format
		switch(currDesc.format)
		{
			case DATA_FORMAT_R32G32B32A32_FLOAT:
			case DATA_FORMAT_R32G32B32_FLOAT:
			case DATA_FORMAT_R32G32_FLOAT:
			case DATA_FORMAT_R32_FLOAT:
				dataType=GL_FLOAT;
				sizeInBytes=sizeof(float);
				break;
			case DATA_FORMAT_R32G32B32A32_UINT:
			case DATA_FORMAT_R32G32B32_UINT:
			case DATA_FORMAT_R32G32_UINT:
			case DATA_FORMAT_R32_UINT:
				dataType=GL_INT;
				sizeInBytes=sizeof(int);
				break;
			case DATA_FORMAT_R32G32B32A32_SINT:
			case DATA_FORMAT_R32G32B32_SINT:
			case DATA_FORMAT_R32G32_SINT:
			case DATA_FORMAT_R32_SINT:
				dataType=GL_UNSIGNED_INT;
				sizeInBytes=sizeof(unsigned int);
				break;
		};

		//find the correct size
		switch(currDesc.format)
		{
			case DATA_FORMAT_R32G32B32A32_FLOAT:
			case DATA_FORMAT_R32G32B32A32_UINT:
			case DATA_FORMAT_R32G32B32A32_SINT:
				dataSize=4;
				break;
			case DATA_FORMAT_R32G32B32_FLOAT:
			case DATA_FORMAT_R32G32B32_UINT:
			case DATA_FORMAT_R32G32B32_SINT:
				dataSize=3;
				break;
			case DATA_FORMAT_R32G32_FLOAT:
			case DATA_FORMAT_R32G32_UINT:
			case DATA_FORMAT_R32G32_SINT:
				dataSize=2;
				break;
			case DATA_FORMAT_R32_FLOAT:
			case DATA_FORMAT_R32_UINT:
			case DATA_FORMAT_R32_SINT:
				dataSize=1;
				break;			
		};

		glEnableVertexAttribArray(currDesc.type);
		glVertexAttribPointer(currDesc.type, dataSize, dataType, GL_FALSE, strides, (const GLvoid *)currentOffset);

		//update the current offset
		currentOffset+=dataSize*sizeInBytes;
	}
}

//sets index buffer
void graphicsGL::deviceContextGL::setIndexBuffer(bufferBase *bufferData, graphicsDefinitions::DATA_FORMAT format, unsigned int offset)
{
	bufferGL *bufferDataGL=(bufferGL *)bufferData;

	//bind the index buffer
	glBindBuffer(bufferDataGL->target, bufferDataGL->glBuffer);

	using namespace graphicsDefinitions;
	//find the correct format
	switch(format)
	{
		case DATA_FORMAT_R32G32B32A32_FLOAT:
		case DATA_FORMAT_R32G32B32_FLOAT:
		case DATA_FORMAT_R32G32_FLOAT:
		case DATA_FORMAT_R32_FLOAT:
		case DATA_FORMAT_R32G32B32A32_UINT:
		case DATA_FORMAT_R32G32B32_UINT:
		case DATA_FORMAT_R32G32_UINT:
		case DATA_FORMAT_R32_UINT:
		case DATA_FORMAT_R32G32B32A32_SINT:
		case DATA_FORMAT_R32G32B32_SINT:
		case DATA_FORMAT_R32G32_SINT:
		case DATA_FORMAT_R32_SINT:
			indexDataType=GL_UNSIGNED_INT;
			break;
		case DATA_FORMAT_R16_SINT:
		case DATA_FORMAT_R16_UINT:
			indexDataType=GL_UNSIGNED_SHORT;
			break;
		case DATA_FORMAT_R8_SINT:
		case DATA_FORMAT_R8_UINT:
			indexDataType=GL_UNSIGNED_BYTE;
			break;

	};
}

//sets primitive topology
void graphicsGL::deviceContextGL::setPrimitiveTopology(graphicsDefinitions::PRIMITIVE_TOPOLOGY topology)
{
	using namespace graphicsDefinitions;
	switch(topology)
	{
		case PRIMITIVE_TOPOLOGY_UNDEFINED                 : break; 
		case PRIMITIVE_TOPOLOGY_POINTLIST                 : drawMode=GL_POINTS; break; 
		case PRIMITIVE_TOPOLOGY_LINELIST                  : drawMode=GL_LINES;break; 
		case PRIMITIVE_TOPOLOGY_LINESTRIP                 : drawMode=GL_LINE_STRIP;break; 
		case PRIMITIVE_TOPOLOGY_TRIANGLELIST              : drawMode=GL_TRIANGLES;break; 
		case PRIMITIVE_TOPOLOGY_TRIANGLESTRIP             : drawMode=GL_TRIANGLE_STRIP;break; 
		case PRIMITIVE_TOPOLOGY_LINELIST_ADJ              : drawMode=GL_LINES_ADJACENCY;break; 
		case PRIMITIVE_TOPOLOGY_LINESTRIP_ADJ             : drawMode=GL_LINE_STRIP_ADJACENCY;break; 
		case PRIMITIVE_TOPOLOGY_TRIANGLELIST_ADJ          : drawMode=GL_TRIANGLES_ADJACENCY ;break; 
		case PRIMITIVE_TOPOLOGY_TRIANGLESTRIP_ADJ         : drawMode=GL_TRIANGLE_STRIP_ADJACENCY;break; 
		case PRIMITIVE_TOPOLOGY_1_CONTROL_POINT_PATCHLIST : drawMode=GL_PATCHES; glPatchParameteri(GL_PATCH_VERTICES, 1);break; 
		case PRIMITIVE_TOPOLOGY_2_CONTROL_POINT_PATCHLIST : drawMode=GL_PATCHES; glPatchParameteri(GL_PATCH_VERTICES, 2);break; 
		case PRIMITIVE_TOPOLOGY_3_CONTROL_POINT_PATCHLIST :	drawMode=GL_PATCHES; glPatchParameteri(GL_PATCH_VERTICES, 3);break; 
		case PRIMITIVE_TOPOLOGY_4_CONTROL_POINT_PATCHLIST : drawMode=GL_PATCHES; glPatchParameteri(GL_PATCH_VERTICES, 4);break; 
		case PRIMITIVE_TOPOLOGY_5_CONTROL_POINT_PATCHLIST : drawMode=GL_PATCHES; glPatchParameteri(GL_PATCH_VERTICES, 5);break; 
		case PRIMITIVE_TOPOLOGY_6_CONTROL_POINT_PATCHLIST : drawMode=GL_PATCHES; glPatchParameteri(GL_PATCH_VERTICES, 6);break; 
		case PRIMITIVE_TOPOLOGY_7_CONTROL_POINT_PATCHLIST : drawMode=GL_PATCHES; glPatchParameteri(GL_PATCH_VERTICES, 7);break; 
		case PRIMITIVE_TOPOLOGY_8_CONTROL_POINT_PATCHLIST : drawMode=GL_PATCHES; glPatchParameteri(GL_PATCH_VERTICES, 8);break; 
		case PRIMITIVE_TOPOLOGY_9_CONTROL_POINT_PATCHLIST : drawMode=GL_PATCHES; glPatchParameteri(GL_PATCH_VERTICES, 9);break; 
		case PRIMITIVE_TOPOLOGY_10_CONTROL_POINT_PATCHLIST: drawMode=GL_PATCHES; glPatchParameteri(GL_PATCH_VERTICES, 10);break; 
		case PRIMITIVE_TOPOLOGY_11_CONTROL_POINT_PATCHLIST: drawMode=GL_PATCHES; glPatchParameteri(GL_PATCH_VERTICES, 11);break; 
		case PRIMITIVE_TOPOLOGY_12_CONTROL_POINT_PATCHLIST: drawMode=GL_PATCHES; glPatchParameteri(GL_PATCH_VERTICES, 12);break; 
		case PRIMITIVE_TOPOLOGY_13_CONTROL_POINT_PATCHLIST: drawMode=GL_PATCHES; glPatchParameteri(GL_PATCH_VERTICES, 13);break; 
		case PRIMITIVE_TOPOLOGY_14_CONTROL_POINT_PATCHLIST: drawMode=GL_PATCHES; glPatchParameteri(GL_PATCH_VERTICES, 14);break; 
		case PRIMITIVE_TOPOLOGY_15_CONTROL_POINT_PATCHLIST: drawMode=GL_PATCHES; glPatchParameteri(GL_PATCH_VERTICES, 15);break; 
		case PRIMITIVE_TOPOLOGY_16_CONTROL_POINT_PATCHLIST: drawMode=GL_PATCHES; glPatchParameteri(GL_PATCH_VERTICES, 16);break; 
		case PRIMITIVE_TOPOLOGY_17_CONTROL_POINT_PATCHLIST: drawMode=GL_PATCHES; glPatchParameteri(GL_PATCH_VERTICES, 17);break; 
		case PRIMITIVE_TOPOLOGY_18_CONTROL_POINT_PATCHLIST: drawMode=GL_PATCHES; glPatchParameteri(GL_PATCH_VERTICES, 18);break; 
		case PRIMITIVE_TOPOLOGY_19_CONTROL_POINT_PATCHLIST: drawMode=GL_PATCHES; glPatchParameteri(GL_PATCH_VERTICES, 19);break; 
		case PRIMITIVE_TOPOLOGY_20_CONTROL_POINT_PATCHLIST: drawMode=GL_PATCHES; glPatchParameteri(GL_PATCH_VERTICES, 20);break; 
		case PRIMITIVE_TOPOLOGY_21_CONTROL_POINT_PATCHLIST: drawMode=GL_PATCHES; glPatchParameteri(GL_PATCH_VERTICES, 21);break; 
		case PRIMITIVE_TOPOLOGY_22_CONTROL_POINT_PATCHLIST: drawMode=GL_PATCHES; glPatchParameteri(GL_PATCH_VERTICES, 22);break; 
		case PRIMITIVE_TOPOLOGY_23_CONTROL_POINT_PATCHLIST: drawMode=GL_PATCHES; glPatchParameteri(GL_PATCH_VERTICES, 23);break; 
		case PRIMITIVE_TOPOLOGY_24_CONTROL_POINT_PATCHLIST: drawMode=GL_PATCHES; glPatchParameteri(GL_PATCH_VERTICES, 23);break; 
		case PRIMITIVE_TOPOLOGY_25_CONTROL_POINT_PATCHLIST: drawMode=GL_PATCHES; glPatchParameteri(GL_PATCH_VERTICES, 23);break; 
		case PRIMITIVE_TOPOLOGY_26_CONTROL_POINT_PATCHLIST: drawMode=GL_PATCHES; glPatchParameteri(GL_PATCH_VERTICES, 24);break; 
		case PRIMITIVE_TOPOLOGY_27_CONTROL_POINT_PATCHLIST: drawMode=GL_PATCHES; glPatchParameteri(GL_PATCH_VERTICES, 25);break; 
		case PRIMITIVE_TOPOLOGY_28_CONTROL_POINT_PATCHLIST: drawMode=GL_PATCHES; glPatchParameteri(GL_PATCH_VERTICES, 26);break; 
		case PRIMITIVE_TOPOLOGY_29_CONTROL_POINT_PATCHLIST: drawMode=GL_PATCHES; glPatchParameteri(GL_PATCH_VERTICES, 27);break; 
		case PRIMITIVE_TOPOLOGY_30_CONTROL_POINT_PATCHLIST: drawMode=GL_PATCHES; glPatchParameteri(GL_PATCH_VERTICES, 28);break; 
		case PRIMITIVE_TOPOLOGY_31_CONTROL_POINT_PATCHLIST: drawMode=GL_PATCHES; glPatchParameteri(GL_PATCH_VERTICES, 29);break; 
		case PRIMITIVE_TOPOLOGY_32_CONTROL_POINT_PATCHLIST: drawMode=GL_PATCHES; glPatchParameteri(GL_PATCH_VERTICES, 30);break; 
	};

}

//Draw non-indexed, non-instanced primitives
void graphicsGL::deviceContextGL::draw(unsigned int vertexCount,unsigned int startVertexLocation)
{
	glDrawArrays(drawMode, startVertexLocation, vertexCount);
}
//draw indexed primitive
void graphicsGL::deviceContextGL::drawIndexed(unsigned int indexCount,unsigned int startIndexLocation,int baseVertexLocation)
{
	glDrawElements(drawMode, indexCount, indexDataType, (const GLvoid *)startIndexLocation);
}
//Draw non-indexed, instanced primitives.
void graphicsGL::deviceContextGL::drawInstanced(unsigned int vertexCountPerInstance,unsigned int instanceCount,unsigned int startVertexLocation,unsigned int startInstanceLocation)
{
	//TODO
}
//Draw indexed, instanced primitives.
void graphicsGL::deviceContextGL::drawIndexedInstanced(unsigned int indexCountPerInstance,unsigned int instanceCount,unsigned int startIndexLocation,int baseVertexLocation,unsigned int startInstanceLocation)
{
	//TODO
}
//Draw instanced, GPU-generated primitives.
void graphicsGL::deviceContextGL::drawInstancedIndirect(bufferBase *pBufferForArgs,unsigned int alignedByteOffsetForArgs)
{
	//TODO
}
//Draw indexed, instanced, GPU-generated primitives.
void graphicsGL::deviceContextGL::drawIndexedInstancedIndirect(bufferBase *pBufferForArgs,unsigned int alignedByteOffsetForArgs)
{
	//TODO
}

//clear the render target
void graphicsGL::deviceContextGL::clearRenderTargetView(renderTargetViewBase *rTargetView, float *clearColor)
{
	//set the clear color
	glClearColor(clearColor[0],clearColor[1],clearColor[2],clearColor[3]);

	//clear color
	glClear(GL_COLOR_BUFFER_BIT);
}

//Clears the depth-stencil resource
void graphicsGL::deviceContextGL::clearDepthStencilView(depthStencilViewBase *dStencilView,unsigned int clearFlags, float depth, unsigned int stencil)
{
	//set the depth value
	glClearDepth(depth);

	//set the stencil value
	glClearStencil(stencil);

	//clear depth
	glClear(GL_DEPTH_BUFFER_BIT|GL_STENCIL_BUFFER_BIT);
}


//set constant buffer in pixel shader
void graphicsGL::deviceContextGL::VSSetConstantBuffers(unsigned int startSlot,unsigned int numBuffers, bufferBase *constantBuffers, unsigned int uniformIndex)
{
	bufferGL *bDataGL=(bufferGL *)constantBuffers;

	//bind buffer to index buffer target
	glBindBufferBase(bDataGL->target, startSlot, bDataGL->glBuffer);
	
	//assign binding point to an active uniform block
	glUniformBlockBinding(shaderObject, uniformIndex, startSlot);	
}
//set constant buffer in hull shader
void graphicsGL::deviceContextGL::HSSetConstantBuffers(unsigned int startSlot,unsigned int numBuffers, bufferBase *constantBuffers, unsigned int uniformIndex)
{
	VSSetConstantBuffers(startSlot,numBuffers,constantBuffers,uniformIndex);
}
//set constant buffer in domain shader
void graphicsGL::deviceContextGL::DSSetConstantBuffers(unsigned int startSlot,unsigned int numBuffers, bufferBase *constantBuffers, unsigned int uniformIndex)
{
	VSSetConstantBuffers(startSlot,numBuffers,constantBuffers,uniformIndex);
}
//set constant buffer in geometry shader
void graphicsGL::deviceContextGL::GSSetConstantBuffers(unsigned int startSlot,unsigned int numBuffers, bufferBase *constantBuffers, unsigned int uniformIndex)
{
	VSSetConstantBuffers(startSlot,numBuffers,constantBuffers,uniformIndex);
}
//set constant buffer in pixel shader
void graphicsGL::deviceContextGL::PSSetConstantBuffers(unsigned int startSlot,unsigned int numBuffers, bufferBase *constantBuffers, unsigned int uniformIndex)
{
	VSSetConstantBuffers(startSlot,numBuffers,constantBuffers,uniformIndex);
}
//set constant buffer in compute shader
void graphicsGL::deviceContextGL::CSSetConstantBuffers(unsigned int startSlot,unsigned int numBuffers, bufferBase *constantBuffers, unsigned int uniformIndex)
{
	bufferGL *bDataGL=(bufferGL *)constantBuffers;

	//TODO
}


//set shader resource in pixel shader
void graphicsGL::deviceContextGL::VSSetShaderResources(unsigned int startSlot,unsigned int numViews, shaderResourceViewBase *shaderResources, unsigned int uniformIndex)
{
	shaderResourceViewGL *bDataGL=(shaderResourceViewGL *)shaderResources;
	
	glActiveTexture(GL_TEXTURE0+startSlot);

	bufferGL *bufferDatasGL=dynamic_cast<bufferGL *>(bDataGL->resourcePtr);
	if(bufferDatasGL!=NULL)
		glBindBuffer(bufferDatasGL->target, bufferDatasGL->glBuffer);//bind the buffer

	texture2DGL *texture2GL=dynamic_cast<texture2DGL *>(bDataGL->resourcePtr);
	if(texture2GL!=NULL)
		glBindTexture(texture2GL->textureTarget, texture2GL->data);//bind the texture

	glUniform1i(uniformIndex,startSlot);
}
//set shader resource in hull shader
void graphicsGL::deviceContextGL::HSSetShaderResources(unsigned int startSlot,unsigned int numViews, shaderResourceViewBase *shaderResources, unsigned int uniformIndex)
{
	VSSetShaderResources(startSlot,numViews,shaderResources,uniformIndex);
}
//set shader resource in domain shader
void graphicsGL::deviceContextGL::DSSetShaderResources(unsigned int startSlot,unsigned int numViews, shaderResourceViewBase *shaderResources, unsigned int uniformIndex)
{
	VSSetShaderResources(startSlot,numViews,shaderResources,uniformIndex);
}
//set shader resource in geometry shader
void graphicsGL::deviceContextGL::GSSetShaderResources(unsigned int startSlot,unsigned int numViews, shaderResourceViewBase *shaderResources, unsigned int uniformIndex)
{
	VSSetShaderResources(startSlot,numViews,shaderResources,uniformIndex);
}
//set shader resource in pixel shader
void graphicsGL::deviceContextGL::PSSetShaderResources(unsigned int startSlot,unsigned int numViews, shaderResourceViewBase *shaderResources, unsigned int uniformIndex)
{
	VSSetShaderResources(startSlot,numViews,shaderResources,uniformIndex);	
}
//set shader resource in compute shader
void graphicsGL::deviceContextGL::CSSetShaderResources(unsigned int startSlot,unsigned int numViews, shaderResourceViewBase *shaderResources, unsigned int uniformIndex)
{
	shaderResourceViewGL *bDataGL=(shaderResourceViewGL *)shaderResources;
	bufferGL *bufferPtr=(bufferGL *)bDataGL->resourcePtr;

	if(!bufferPtr || bufferPtr->bufferType!=bufferGL::BUFFER_TYPE_CL)
		return;
	
	//set the buffer
	if(clSetKernelArg(attachedComputeShader, startSlot, sizeof(cl_mem), (void*)&bufferPtr->clBuffer)!=CL_SUCCESS)
	{
		outputDebugString("%s(%d): Error: assigning kernel argument.\n",__FILE__,__LINE__);
		return;
	}
}

//set unordered access view in compute shader
void graphicsGL::deviceContextGL::CSSetUnorderedAccessViews(unsigned int startSlot,unsigned int numUAVs, unorderedAccessViewBase *uavResources,unsigned int *initialCounts)
{
	unorderedAccessViewGL *uavResourcesGL=(unorderedAccessViewGL *)uavResources;
	bufferGL *bufferPtr=(bufferGL *)uavResourcesGL->resourcePtr;
	
	if(!bufferPtr || bufferPtr->bufferType!=bufferGL::BUFFER_TYPE_CL)
		return;
	
	//set the buffer
	if(clSetKernelArg(attachedComputeShader, startSlot, sizeof(cl_mem), (void*)&bufferPtr->clBuffer)!=CL_SUCCESS)
	{
		outputDebugString("%s(%d): Error: assigning kernel argument.\n",__FILE__,__LINE__);
		return;
	}
}

//execute direct compute command list from a thread group
void graphicsGL::deviceContextGL::dispatch(unsigned int threadGroupCountX, unsigned int threadGroupCountY, unsigned int threadGroupCountZ)
{
	//execute the compute shader in number of targets
	//to do make it work in more than 1d came
	size_t size=threadGroupCountX;
	size_t workGroupSize=size;
	size_t localWorkSize=size;
	if(clEnqueueNDRangeKernel(clCommandQueue, attachedComputeShader, 1, NULL, &workGroupSize, &localWorkSize, 0, NULL, NULL) != CL_SUCCESS)
		outputDebugString("%s(%d): Error: running Kernel.\n",__FILE__,__LINE__);
		
	//{
	//const unsigned int size=256;
	//unsigned int dataIn[size];

	//for(unsigned int i=0;i<size;i++)
	//	dataIn[i]=i;
	//	unsigned int dataOut[size];		

	//	int errorCode;
	//	cl_mem computeBufferIn = clCreateBuffer(gDevice->clContext, CL_MEM_READ_WRITE|CL_MEM_COPY_HOST_PTR, sizeof(int) * size, dataIn, &errorCode);
	//	if(errorCode!=CL_SUCCESS)
	//	{
	//		outputDebugString("Error allocating openCL memory.\n");
	//		return false;
	//	}

	//	////copy the data to gpu
	//	//if(clEnqueueWriteBuffer(dContext->clCommandQueue, computeBufferIn, CL_FALSE, 0, sizeof(int) * size, dataIn, 0, NULL, NULL)!=CL_SUCCESS)
	//	//{
	//	//	outputDebugString("Error copying the data.\n");
	//	//	clReleaseMemObject(computeBufferIn);
	//	//	return false;
	//	//}

	//	cl_mem computeBufferOut = clCreateBuffer(gDevice->clContext, CL_MEM_READ_WRITE, sizeof(int) * size, NULL, &errorCode);
	//	if(errorCode!=CL_SUCCESS)
	//	{
	//		outputDebugString("Error allocating openCL memory.\n");
	//		clReleaseMemObject(computeBufferIn);
	//		return false;
	//	}

	//	//assign shader arguments
	//	//nvidia driver error or feature, if i put CL_MEM_READ_ONLY and write in it, it is valid.
	//	errorCode = clSetKernelArg(cShader->clKernel, 0, sizeof(cl_mem), (void*)&computeBufferIn);
	//	errorCode |= clSetKernelArg(cShader->clKernel, 1, sizeof(cl_mem), (void*)&computeBufferOut);
	//	//errorCode |= clSetKernelArg(cShader->clKernel, 2, sizeof(cl_int), (void*)&size);

	//	if(errorCode!=CL_SUCCESS)
	//	{
	//		outputDebugString("Error assigning kernel argument.\n");
	//		clReleaseMemObject(computeBufferIn);
	//		clReleaseMemObject(computeBufferOut);
	//		return false;
	//	}

	//	//launch kernel
	//	size_t workGroupSize=size;
	//	size_t localWorkSize=size;
	//	if(clEnqueueNDRangeKernel(dContext->clCommandQueue, cShader->clKernel, 1, NULL, &workGroupSize, &localWorkSize, 0, NULL, NULL) != CL_SUCCESS)
	//	{
	//		outputDebugString("Error running Kernel.\n");
	//		clReleaseMemObject(computeBufferIn);
	//		clReleaseMemObject(computeBufferOut);
	//		return false;
	//	}

	//	// Synchronous/blocking read of results, and check accumulated errors
	//	if(clEnqueueReadBuffer(dContext->clCommandQueue, computeBufferIn, CL_TRUE, 0, sizeof(int) * size, dataOut, 0, NULL, NULL) != CL_SUCCESS)
	//	{
	//		outputDebugString("Error running Kernel.\n");
	//		clReleaseMemObject(computeBufferIn);
	//		clReleaseMemObject(computeBufferOut);
	//		return false;
	//	}

	//	for(unsigned int i=0;i<size;i++)
	//	{
	//		if(dataOut[i]!=i)
	//			outputDebugString("Error in compute shader.\n");
	//	}
	//	outputDebugString("Compute shader completed.\n");
	//

	//	clReleaseMemObject(computeBufferIn);
	//	clReleaseMemObject(computeBufferOut);
	//}

}


//set sampler in pixel shader
void graphicsGL::deviceContextGL::VSSetSamplers(unsigned int startSlot,unsigned int numSamplers, samplerStateBase *samplers)
{
	samplerStateGL *samplersGL=(samplerStateGL *)samplers;

	//activate the texture
	glActiveTexture(GL_TEXTURE0+startSlot);

	//bind the sampler
	glBindSampler(startSlot, samplersGL->data);	
}
//set sampler in hull shader
void graphicsGL::deviceContextGL::HSSetSamplers(unsigned int startSlot,unsigned int numSamplers, samplerStateBase *samplers)
{
	VSSetSamplers(startSlot,numSamplers,samplers);
}
//set sampler in domain shader
void graphicsGL::deviceContextGL::DSSetSamplers(unsigned int startSlot,unsigned int numSamplers, samplerStateBase *samplers)
{
	VSSetSamplers(startSlot,numSamplers,samplers);
}
//set sampler in geometry shader
void graphicsGL::deviceContextGL::GSSetSamplers(unsigned int startSlot,unsigned int numSamplers, samplerStateBase *samplers)
{
	VSSetSamplers(startSlot,numSamplers,samplers);
}
//set sampler in pixel shader
void graphicsGL::deviceContextGL::PSSetSamplers(unsigned int startSlot,unsigned int numSamplers, samplerStateBase *samplers)
{
	VSSetSamplers(startSlot,numSamplers,samplers);	
}
//set sampler in compute shader
void graphicsGL::deviceContextGL::CSSetSamplers(unsigned int startSlot,unsigned int numSamplers, samplerStateBase *samplers)
{
	samplerStateGL *bDataGL=(samplerStateGL *)samplers;
}

//set vertex shader
void graphicsGL::deviceContextGL::VSSetShader(shaderVertexBase *shader, classInstanceBase *classInstances,unsigned int numClassInstances)
{	
	shaderVertexGL *shaderGL=(shaderVertexGL *)shader;

	if(shaderGL && attachedShaders[graphicsDefinitions::SHADER_TYPE_VERTEX] == shaderGL->data)
		return;

	//remove the old shader
	if(attachedShaders[graphicsDefinitions::SHADER_TYPE_VERTEX])
		glDetachShader(shaderObject, attachedShaders[graphicsDefinitions::SHADER_TYPE_VERTEX]);
	
	if(!shaderGL)
	{
		attachedShaders[graphicsDefinitions::SHADER_TYPE_VERTEX] = NULL;
		return;
	}

	//save the data
	attachedShaders[graphicsDefinitions::SHADER_TYPE_VERTEX]=shaderGL->data;

	//attach the shader
	glAttachShader(shaderObject, shaderGL->data);
}
//set hull shader
void graphicsGL::deviceContextGL::HSSetShader(shaderHullBase *shader, classInstanceBase *classInstances,unsigned int numClassInstances)
{
	shaderHullGL *shaderGL=(shaderHullGL *)shader;
		
	if(shaderGL && attachedShaders[graphicsDefinitions::SHADER_TYPE_HULL] == shaderGL->data)
		return;

	//remove the old shader
	if(attachedShaders[graphicsDefinitions::SHADER_TYPE_HULL])
		glDetachShader(shaderObject, attachedShaders[graphicsDefinitions::SHADER_TYPE_HULL]);

	if(!shaderGL)
	{
		attachedShaders[graphicsDefinitions::SHADER_TYPE_HULL] = NULL;
		return;
	}

	//save the data
	attachedShaders[graphicsDefinitions::SHADER_TYPE_HULL]=shaderGL->data;

	//attach the shader
	glAttachShader(shaderObject, shaderGL->data);
}
//set domain shader
void graphicsGL::deviceContextGL::DSSetShader(shaderDomainBase *shader, classInstanceBase *classInstances,unsigned int numClassInstances)
{
	shaderDomainGL *shaderGL=(shaderDomainGL *)shader;
	
	if(shaderGL && attachedShaders[graphicsDefinitions::SHADER_TYPE_DOMAIN] == shaderGL->data)
		return;

	//remove the old shader
	if(attachedShaders[graphicsDefinitions::SHADER_TYPE_DOMAIN])
		glDetachShader(shaderObject, attachedShaders[graphicsDefinitions::SHADER_TYPE_DOMAIN]);

	if(!shaderGL)
	{
		attachedShaders[graphicsDefinitions::SHADER_TYPE_DOMAIN] = NULL;
		return;
	}

	//save the data
	attachedShaders[graphicsDefinitions::SHADER_TYPE_DOMAIN]=shaderGL->data;
	
	//attach the shader
	glAttachShader(shaderObject, shaderGL->data);
}
//set geometry shader
void graphicsGL::deviceContextGL::GSSetShader(shaderGeometryBase *shader, classInstanceBase *classInstances,unsigned int numClassInstances)
{
	shaderGeometryGL *shaderGL=(shaderGeometryGL *)shader;
	
	if(shaderGL && attachedShaders[graphicsDefinitions::SHADER_TYPE_GEOMETRY] == shaderGL->data)
		return;

	//remove the old shader
	if(attachedShaders[graphicsDefinitions::SHADER_TYPE_GEOMETRY])
		glDetachShader(shaderObject, attachedShaders[graphicsDefinitions::SHADER_TYPE_GEOMETRY]);

	if(!shaderGL)
	{
		attachedShaders[graphicsDefinitions::SHADER_TYPE_GEOMETRY] = NULL;
		return;
	}

	//save the data
	attachedShaders[graphicsDefinitions::SHADER_TYPE_GEOMETRY]=shaderGL->data;

	//attach the shader
	glAttachShader(shaderObject, shaderGL->data);
}
//set pixel shader
void graphicsGL::deviceContextGL::PSSetShader(shaderPixelBase *shader, classInstanceBase *classInstances,unsigned int numClassInstances)
{
	shaderPixelGL *shaderGL=(shaderPixelGL *)shader;

	if(shaderGL && attachedShaders[graphicsDefinitions::SHADER_TYPE_PIXEL] == shaderGL->data)
		return;

	//remove the old shader
	if(attachedShaders[graphicsDefinitions::SHADER_TYPE_PIXEL])
		glDetachShader(shaderObject, attachedShaders[graphicsDefinitions::SHADER_TYPE_PIXEL]);

	if(!shaderGL)
	{
		attachedShaders[graphicsDefinitions::SHADER_TYPE_PIXEL] = NULL;
		return;
	}

	//save the data
	attachedShaders[graphicsDefinitions::SHADER_TYPE_PIXEL]=shaderGL->data;

	//attach the shader
	glAttachShader(shaderObject, shaderGL->data);
}
//set compute shader
void graphicsGL::deviceContextGL::CSSetShader(shaderComputeBase *shader, classInstanceBase *classInstances,unsigned int numClassInstances)
{
	shaderComputeGL *shaderGL=(shaderComputeGL *)shader;
	classInstanceGL *classInstancesGL=(classInstanceGL *)classInstances;

	if(shader==NULL)
	{
		attachedComputeShader=NULL;
		return;
	}
		
	if(attachedComputeShader == shaderGL->clKernel)
		return;

	//remove the old shader
	//if(attachedShaders[graphicsDefinitions::SHADER_TYPE_COMPUTE])
		//glDetachShader(shaderObject, attachedShaders[graphicsDefinitions::SHADER_TYPE_COMPUTE]);

	//save the data
	attachedComputeShader=shaderGL->clKernel;

	//attach the shader
	//glAttachShader(shaderObject, shaderGL->data);
}

//checks the shaders status
bool graphicsGL::deviceContextGL::checkShaderLinkStatusGL(unsigned int shaderObjectIDGL)
{
	int result=0,infoLength=0;
	
	//try and validate the program
	glValidateProgram(shaderObjectIDGL);

	//check the status
	glGetProgramiv(shaderObjectIDGL,GL_VALIDATE_STATUS, &result);

	//get length of additional info
	glGetProgramiv(shaderObjectIDGL, GL_INFO_LOG_LENGTH, &infoLength);

	if(infoLength>1)
	{
		char *log=new char[infoLength+1];

		//get the additional info
		glGetProgramInfoLog(shaderObjectIDGL, infoLength, NULL, log);

		//print the output
		outputDebugString("%s(%d): Shader Link Error : %s\n",__FILE__,__LINE__,log);

		delete[] log;
	}

	if(!result)
		return false;

	//check the status
	glGetProgramiv(shaderObjectIDGL,GL_LINK_STATUS, &result);

	//get length of additional info
	glGetProgramiv(shaderObjectIDGL, GL_INFO_LOG_LENGTH, &infoLength);

	if(infoLength>1)
	{
		char *log=new char[infoLength+1];

		//get the additional info
		glGetProgramInfoLog(shaderObjectIDGL, infoLength, NULL, log);

		//print the output
		outputDebugString("%s(%d): Shader Link Error : %s\n",__FILE__,__LINE__,log);

		delete[] log;
	}

	return (result!=0);
}

//called after all the shaders are set before drawing
void graphicsGL::deviceContextGL::shaderBegin(void)
{
	//link the program 
	glLinkProgram(shaderObject);

	//check the status
	checkShaderLinkStatusGL(shaderObject);

	//bind program
	glUseProgram(shaderObject);
}
//called after all the drawing is done
void graphicsGL::deviceContextGL::shaderEnd(void)
{
	
}
//returns uniform block index. only used in opengl
unsigned int graphicsGL::deviceContextGL::getUniformBlockIndex(char *name)
{
	return glGetUniformBlockIndex(shaderObject, name);
}
//returns uniform location. only used in opengl
unsigned int graphicsGL::deviceContextGL::getUniformLocation(char *name)
{
	return glGetUniformLocation(shaderObject, name);
}

//sets rasterizer state
void graphicsGL::deviceContextGL::RSSetState(rasterizerStateBase *rsData)
{
	rasterizerStateGL *rsDataGL=(rasterizerStateGL *)rsData;
	using namespace graphicsDefinitions;

	//set fill mode
	switch(rsDataGL->fillMode)
	{
		case FILL_MODE_SOLID:
			glPolygonMode(GL_FRONT_AND_BACK,GL_FILL);
			break;
		case FILL_MODE_WIREFRAME:
			glPolygonMode(GL_FRONT_AND_BACK,GL_LINE);
			break;
	}
	
	//set cull side
	switch(rsDataGL->cullMode)
	{
		case CULL_MODE_NONE:
			glDisable(GL_CULL_FACE);
			break;
		case CULL_MODE_FRONT:
			glEnable(GL_CULL_FACE);
			glCullFace(GL_FRONT);			
			break;
		case CULL_MODE_BACK:
			glEnable(GL_CULL_FACE);
			glCullFace(GL_BACK);
			break;
	}
		
	if(rsDataGL->frontCounterClockwise)
		glFrontFace(GL_CCW);
	else
		glFrontFace(GL_CW);

	//set the depth bias
	glPolygonOffset(rsDataGL->slopeScaledDepthBias,(float)rsDataGL->depthBias);

	if(rsDataGL->depthClipEnable)
		glEnable(GL_DEPTH_TEST);
	else
		glDisable(GL_DEPTH_TEST);

	if(rsDataGL->scissorEnable)
		glEnable(GL_SCISSOR_TEST);
	else
		glDisable(GL_SCISSOR_TEST);

	if(rsDataGL->multisampleEnable)
		glEnable(GL_MULTISAMPLE);
	else
		glDisable(GL_MULTISAMPLE);

	if(rsDataGL->antialiasedLineEnable)
		glEnable(GL_POLYGON_SMOOTH);
	else
		glDisable(GL_POLYGON_SMOOTH);


}


